package com.biboheart.brick.datetime;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class BhDate implements Serializable, Cloneable {
    // 时间戳
    private long timeMillis = 0L;

    /**
     * 构造函数, 默认取当前时间
     */
    public BhDate() {
        this.timeMillis = System.currentTimeMillis();
    }

    /**
     * 构造函数
     *
     * @param timeMillis
     *            时间戳
     */
    public BhDate(long timeMillis) {
        this.timeMillis = timeMillis;
    }

    /**
     * 构造函数
     *
     * @param timeStr
     *            时间字符串
     */
    public BhDate(String timeStr) {
        this(timeStr, null);
    }

    /**
     * 构造函数
     *
     * @param timeStr
     *            时间字符串
     * @param pattern
     *            时间字符串的格式
     */
    public BhDate(String timeStr, String pattern) {
        if (null == pattern || pattern.isEmpty()) {
            pattern = "yyyy-MM-dd HH:mm:ss";
        }
        Date date = null;
        try {
            date = new SimpleDateFormat(pattern).parse(timeStr);
        } catch (ParseException ignore) {
        }
        this.timeMillis = null == date ? 0 : date.getTime();
    }

    /**
     * 获取实例
     * @param timeMillis 时间戳
     * @return 实例
     */
    public static BhDate getInstance(long timeMillis) {
        return new BhDate(timeMillis);
    }

    /**
     * 取时间戳值
     * @return 时间戳值
     */
    public long valueOf() {
        return timeMillis;
    }

    /**
     * 取某个单位的值
     * @param dateUnit 时间单位
     * @return 某个单位的值
     */
    public int get(BhDateUnit dateUnit) {
        switch (dateUnit) {
            case DATE_UNIT_YEAR:
                return this.getYear();
            case DATE_UNIT_MONTH:
                return this.getMonth();
            case DATE_UNIT_DAY:
                return this.getDay();
            case DATE_UNIT_HOUR:
                return this.getHour();
            case DATE_UNIT_MINUTE:
                return this.getMinute();
            case DATE_UNIT_SECOND:
                return this.getSecond();
            case DATE_UNIT_MILLISECOND:
                return this.getMillis();
            case DATE_UNIT_WEEK:
                return this.getWeek();
            default:
                return 0;
        }
    }

    /**
     * 取年份
     * @return 年份
     */
    public int getYear() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 取月份
     * @return 月份
     */
    public int getMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 取日期
     * @return 日期
     */
    public int getDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 取小时
     * @return 小时
     */
    public int getHour() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    /**
     * 取分钟
     * @return 分钟
     */
    public int getMinute() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.MINUTE);
    }

    /**
     * 取秒
     * @return 秒
     */
    public int getSecond() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.SECOND);
    }

    /**
     * 取毫秒
     * @return 毫秒
     */
    public int getMillis() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.MILLISECOND);
    }

    /**
     * 取星期
     * @return 星期
     */
    public int getWeek() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 格式化时间成字符串
     * @return 时间字符串
     */
    public String format() {
        return this.format(null);
    }

    /**
     * 格式化时间成字符串
     * @param pattern
     *            时间字符串的格式
     * @return 时间字符串
     */
    public String format(String pattern) {
        if (null == pattern || pattern.isEmpty()) {
            pattern = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(this.timeMillis);
    }

    /**
     * 取Date对象
     * @return Date对象
     */
    public Date toDate() {
        return new Date(this.timeMillis);
    }

    /**
     * 比较两个时间的差值
     * @param target 目标对象
     * @param dateUnit 时间单位
     * @return 时间差值
     */
    public int diff(BhDate target, BhDateUnit dateUnit) {
        long base = 1L;
        switch (dateUnit) {
            case DATE_UNIT_YEAR:
                base = 31536000000L;
                break;
            case DATE_UNIT_MONTH:
                base = 2592000000L;
                break;
            case DATE_UNIT_WEEK:
                base = 604800000L;
                break;
            case DATE_UNIT_DAY:
                base = 86400000L;
                break;
            case DATE_UNIT_HOUR:
                base = 3600000L;
                break;
            case DATE_UNIT_MINUTE:
                base = 60000L;
                break;
            case DATE_UNIT_SECOND:
                base = 1000L;
                break;
            case DATE_UNIT_MILLISECOND:
                break;
        }
        long diff = this.timeMillis - target.timeMillis;
        return (int) (diff / base);
    }

    /**
     * 取Calendar对象
     * @return Calendar对象
     */
    public Calendar toCalendar() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        return calendar;
    }

    /**
     * 克隆对象
     * @return 克隆后的对象
     */
    @Override
    public BhDate clone() {
        try {
            return (BhDate) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    /**
     * 增加时间
     * @param dateUnit
     *            时间单位
     * @param value
     *            增加的值
     * @return this
     */
    public BhDate add(BhDateUnit dateUnit, int value) {
        switch (dateUnit) {
            case DATE_UNIT_YEAR:
                this.addYears(value);
                break;
            case DATE_UNIT_MONTH:
                this.addMonths(value);
                break;
            case DATE_UNIT_DAY:
                this.addDays(value);
                break;
            case DATE_UNIT_HOUR:
                this.addHours(value);
                break;
            case DATE_UNIT_MINUTE:
                this.addMinutes(value);
                break;
            case DATE_UNIT_SECOND:
                this.addSeconds(value);
                break;
            case DATE_UNIT_MILLISECOND:
                this.addMillis(value);
                break;
            case DATE_UNIT_WEEK:
                this.addWeeks(value);
                break;
        }
        return this;
    }

    /**
     * 增加年数
     * @param years 年数
     * @return this
     */
    public BhDate addYears(int years) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.add(Calendar.YEAR, years);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 增加月数
     * @param months 月数
     * @return this
     */
    public BhDate addMonths(int months) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.add(Calendar.MONTH, months);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 增加周数
     * @param weeks 周数
     * @return this
     */
    public BhDate addWeeks(int weeks) {
        this.timeMillis += weeks * 604800000L;
        return this;
    }

    /**
     * 增加天数
     * @param days 天数
     * @return this
     */
    public BhDate addDays(int days) {
        this.timeMillis += days * 86400000L;
        return this;
    }

    /**
     * 增加小时数
     * @param hours 小时数
     * @return this
     */
    public BhDate addHours(int hours) {
        this.timeMillis += hours * 3600000L;
        return this;
    }

    /**
     * 增加分钟数
     * @param minutes 分钟数
     * @return this
     */
    public BhDate addMinutes(int minutes) {
        this.timeMillis += minutes * 60000L;
        return this;
    }

    /**
     * 增加秒数
     * @param seconds 秒数
     * @return this
     */
    public BhDate addSeconds(int seconds) {
        this.timeMillis += seconds * 1000L;
        return this;
    }

    /**
     * 增加毫秒数
     * @param millis 毫秒数
     * @return this
     */
    public BhDate addMillis(int millis) {
        this.timeMillis += millis;
        return this;
    }

    /**
     * 设置时间
     * @param dateUnit
     *            时间单位
     * @param value
     *            设置的值
     * @return this
     */
    public BhDate set(BhDateUnit dateUnit, int value) {
        switch (dateUnit) {
            case DATE_UNIT_YEAR:
                this.setYear(value);
                break;
            case DATE_UNIT_MONTH:
                this.setMonth(value);
                break;
            case DATE_UNIT_DAY:
                this.setDay(value);
                break;
            case DATE_UNIT_HOUR:
                this.setHour(value);
                break;
            case DATE_UNIT_MINUTE:
                this.setMinute(value);
                break;
            case DATE_UNIT_SECOND:
                this.setSecond(value);
                break;
            case DATE_UNIT_MILLISECOND:
                this.setMillis(value);
                break;
        }
        return this;
    }

    /**
     * 设置年
     * @param year 年
     * @return this
     */
    public BhDate setYear(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.YEAR, year);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 设置月
     * @param month 月
     * @return this
     */
    public BhDate setMonth(int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.MONTH, month - 1);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 设置日
     * @param day 日
     * @return this
     */
    public BhDate setDay(int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 设置时
     * @param hour 时
     * @return this
     */
    public BhDate setHour(int hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 设置分
     * @param minute 分
     * @return this
     */
    public BhDate setMinute(int minute) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.MINUTE, minute);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 设置秒
     * @param second 秒
     * @return this
     */
    public BhDate setSecond(int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.SECOND, second);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 设置毫秒
     * @param millis 毫秒
     * @return this
     * */
    public BhDate setMillis(int millis) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(this.timeMillis);
        calendar.set(Calendar.MILLISECOND, millis);
        this.timeMillis = calendar.getTimeInMillis();
        return this;
    }

    /**
     * 开始时间
     * @param dateUnit 时间单位
     * @return this
     */
    public BhDate startOf(BhDateUnit dateUnit) {
        switch (dateUnit) {
            case DATE_UNIT_YEAR:
                this.setMonth(1).setDay(1).setHour(0).setMinute(0).setSecond(0).setMillis(0);
                break;
            case DATE_UNIT_MONTH:
                this.setDay(1).setHour(0).setMinute(0).setSecond(0).setMillis(0);
                break;
            case DATE_UNIT_DAY:
                this.setHour(0).setMinute(0).setSecond(0).setMillis(0);
                break;
        }
        return this;
    }

    /**
     * 结束时间
     * @param dateUnit 时间单位
     * @return this
     */
    public BhDate endOf(BhDateUnit dateUnit) {
        switch (dateUnit) {
            case DATE_UNIT_YEAR:
                this.setMonth(12).setDay(31).setHour(23).setMinute(59).setSecond(59).setMillis(999);
                break;
            case DATE_UNIT_MONTH:
                this.setDay(1).addMonths(1).addDays(-1).setHour(23).setMinute(59).setSecond(59).setMillis(999);
                break;
            case DATE_UNIT_DAY:
                this.setHour(23).setMinute(59).setSecond(59).setMillis(999);
                break;
        }
        return this;
    }
}
